#include "preHeader.h"
#include "GuildMgr.h"
#include "Session/C2GuildPacketHandler.h"
#include "Session/S2GuildPacketHandler.h"
#include "Session/GameServerMgr.h"
#include "Session/DBPSession.h"
#include "Session/DBPHelper.h"
#include "Game/PacketDispatcher.h"
#include "Game/TransMgr.h"
#include "Game/RPCHelper.h"

GuildMgr::GuildMgr()
: IServerService("GuildMgr")
, sWheelTimerMgr(1, GET_UNIX_TIME)
{
	sCharUpdateInfoBitMask.Resize((int)CharUpdateInfo::Type::Count);
}

GuildMgr::~GuildMgr()
{
	for (auto& pair : m_guilds) {
		delete pair.second;
	}
}

int GuildMgr::HandleClientPacket(uint32 uid, INetPacket& pck)
{
	return sC2GuildPacketHandler.HandlePacket(this, pck, uid);
}

int GuildMgr::HandleServerPacket(INetPacket& pck)
{
	return sS2GuildPacketHandler.HandlePacket(this, pck);
}

WheelTimerMgr *GuildMgr::GetWheelTimerMgr()
{
	return &sWheelTimerMgr;
}

void GuildMgr::Update(uint64 diffTime)
{
	IServerService::UpdateAllPackets();
	AsyncTaskOwner::UpdateTask();
}

void GuildMgr::OnTick()
{
	sWheelTimerMgr.Update(GET_UNIX_TIME);
}

bool GuildMgr::LoadDataFromDB()
{
	NetPacket rpcReqPck(CDBP_LOAD_ALL_GUILD_INFO);
	auto errCode = DBPHelper::RPCBlockInvoke(&sDBPSession, rpcReqPck,
		[=](INetStream& pck) {
		while (!pck.IsReadableEmpty()) {
			GuildInformation guildInfo;
			LoadFromINetStream(guildInfo, pck);
			auto pGuild = new Guild();
			pGuild->SetGuildInfo(std::move(guildInfo));
			m_guilds.emplace(pGuild->GetGuildId(), pGuild);
		}
	}, sDBPSessionUpdate4RPCBlockInvoke);
	if (errCode != RPCErrorNone) {
		return false;
	}
	rpcReqPck.Reset(CDBP_LOAD_ALL_GUILD_MEMBER);
	errCode = DBPHelper::RPCBlockInvoke(&sDBPSession, rpcReqPck,
		[=](INetStream& pck) {
		while (!pck.IsReadableEmpty()) {
			GuildMember guildMember;
			LoadFromINetStream(guildMember, pck);
			auto itr = m_guilds.find(guildMember.guildId);
			if (itr != m_guilds.end()) {
				itr->second->AddGuildMember(std::move(guildMember));
			}
		}
	}, sDBPSessionUpdate4RPCBlockInvoke);
	if (errCode != RPCErrorNone) {
		return false;
	}
	rpcReqPck.Reset(CDBP_LOAD_ALL_GUILD_APPLY);
	errCode = DBPHelper::RPCBlockInvoke(&sDBPSession, rpcReqPck,
		[=](INetStream& pck) {
		while (!pck.IsReadableEmpty()) {
			GuildApply guildApply;
			LoadFromINetStream(guildApply, pck);
			auto itr = m_guilds.find(guildApply.guildId);
			if (itr != m_guilds.end()) {
				itr->second->AddGuildApply(std::move(guildApply));
			}
		}
	}, sDBPSessionUpdate4RPCBlockInvoke);
	if (errCode != RPCErrorNone) {
		return false;
	}
	for (auto& pair : m_guilds) {
		pair.second->OnLoadDataFromDBFinished();
	}
	PushAllGuildRankDatas();
	return true;
}

void GuildMgr::CreateGuild(uint32 gsId, uint32 playerId, uint32 guildId, const std::string_view& guildName)
{
	GuildInformation guildInfo;
	guildInfo.Id = guildId;
	guildInfo.gsId = gsId;
	guildInfo.name = guildName;
	guildInfo.createTime = GET_UNIX_TIME;
	guildInfo.level = 1;
	guildInfo.levelTime = GET_UNIX_TIME;

	GuildMember guildMember;
	guildMember.playerId = playerId;
	guildMember.guildId = guildId;
	guildMember.guildTitle = (s8)GUILD_TITLE::MASTER;
	guildMember.joinTime = GET_UNIX_TIME;

	auto pGuild = new Guild();
	pGuild->SetGuildInfo(std::move(guildInfo));
	pGuild->AddGuildMember(std::move(guildMember));
	pGuild->OnLoadDataFromDBFinished();
	m_guilds.emplace(pGuild->GetGuildId(), pGuild);

	const GuildMember* pGuildMember = NULL;
	std::tie(pGuild, pGuildMember) = GetGuildAndMemeber(playerId, guildId);

	NetPacket rpcReqPck(CDBP_NEW_ONE_GUILD_INSTANCE);
	SaveToINetStream(pGuild->GetGuildInformation(), rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);
	rpcReqPck.Reset(CDBP_NEW_ONE_GUILD_MEMBER);
	SaveToINetStream(*pGuildMember, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);

	RemoveInviteApplyRelation(playerId);
	PushPlayerJoinGuild(*pGuildMember, pGuild, GUILD_JOIN_CAUSE::CREATE);
	NewGuildRankData(pGuild);
}

void GuildMgr::DisbandGuild(Guild* pGuild, uint32 playerId)
{
	NetPacket rpcReqPck(CDBP_DELETE_GUILD_APPLY);
	rpcReqPck << u32(0) << pGuild->GetGuildId();
	sDBPSession.RPCInvoke(rpcReqPck);

	auto& guildInvites = pGuild->GetGuildInvites();
	for (auto itr = guildInvites.begin(); itr != guildInvites.end();) {
		auto playerId = itr++->first;
		pGuild->RemoveGuildInvite(playerId);
	}

	auto& guildMembers = pGuild->GetGuildMembers();
	for (auto itr = guildMembers.begin(); itr != guildMembers.end();) {
		auto playerId = itr++->first;
		RemoveGuildMember(pGuild, playerId, GUILD_QUIT_CAUSE::DISBAND);
	}

	rpcReqPck.Reset(CDBP_DELETE_ONE_GUILD_INSTANCE);
	rpcReqPck << pGuild->GetGuildId();
	sDBPSession.RPCInvoke(rpcReqPck);

	RemoveGuildRankData(pGuild);
	m_guilds.erase(pGuild->GetGuildId());
	delete pGuild;
}

void GuildMgr::AddGuildMember(Guild* pGuild, uint32 playerId, GUILD_JOIN_CAUSE cause)
{
	GuildMember guildMember;
	guildMember.playerId = playerId;
	guildMember.guildId = pGuild->GetGuildId();
	guildMember.guildTitle = (s8)GUILD_TITLE::MEMBER;
	guildMember.joinTime = GET_UNIX_TIME;

	pGuild->AddGuildMember(std::move(guildMember));
	const GuildMember* pGuildMember = pGuild->GetGuildMember(playerId);

	NetPacket rpcReqPck(CDBP_NEW_ONE_GUILD_MEMBER);
	SaveToINetStream(*pGuildMember, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);

	RemoveInviteApplyRelation(playerId);
	PushPlayerJoinGuild(*pGuildMember, pGuild, cause);
}

void GuildMgr::RemoveGuildMember(Guild* pGuild, uint32 playerId, GUILD_QUIT_CAUSE cause)
{
	NetPacket rpcReqPck(CDBP_DELETE_ONE_GUILD_MEMBER);
	rpcReqPck << playerId;
	sDBPSession.RPCInvoke(rpcReqPck);
	pGuild->RemoveGuildMember(playerId);
	PushPlayerQuitGuild(playerId, pGuild, cause);
}

void GuildMgr::UpdateGuildInformation(Guild* pGuild, bool isSync2Player)
{
	NetPacket rpcReqPck(CDBP_SAVE_ONE_GUILD_INSTANCE);
	SaveToINetStream(pGuild->GetGuildInformation(), rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);
	for (auto&[playerId, guildMember] : pGuild->GetGuildMembers()) {
		PushPlayerJoinGuild(guildMember, pGuild, GUILD_JOIN_CAUSE::SYNC);
	}
}

void GuildMgr::UpdateGuildMember(Guild* pGuild, const GuildMember& guildMember, GUILD_JOIN_CAUSE cause)
{
	NetPacket rpcReqPck(CDBP_SAVE_ONE_GUILD_MEMBER);
	SaveToINetStream(guildMember, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);
	PushPlayerJoinGuild(guildMember, pGuild, cause);
}

void GuildMgr::PushPlayerJoinGuild(const GuildMember& guildMember, const Guild* pGuild, GUILD_JOIN_CAUSE cause)
{
	NetPacket pack(SGX_CHARACTER_JOIN_GUILD);
	pack << guildMember.playerId << guildMember.guildId << guildMember.guildTitle
		<< pGuild->GetGuildName() << (s8)cause;
	sGameServerMgr.SendPacket2GS(pack);
}

void GuildMgr::PushPlayerQuitGuild(uint32 playerId, const Guild* pGuild, GUILD_QUIT_CAUSE cause)
{
	NetPacket pack(SGX_CHARACTER_QUIT_GUILD);
	pack << playerId << pGuild->GetGuildId() << pGuild->GetGuildName() << (s8)cause;
	sGameServerMgr.SendPacket2GS(pack);
}

void GuildMgr::RemoveInviteApplyRelation(uint32 playerId)
{
	NetPacket rpcReqPck(CDBP_DELETE_GUILD_APPLY);
	rpcReqPck << playerId << u32(0);
	sDBPSession.RPCInvoke(rpcReqPck);
	for (auto&[Id, pGuild] : m_guilds) {
		pGuild->RemoveGuildApply(playerId);
		pGuild->RemoveGuildInvite(playerId);
	}
}

void GuildMgr::OnInviteRelationExpire(uint32 guildId, uint32 playerId)
{
	auto pGuild = GetGuild(guildId);
	if (pGuild != NULL) {
		pGuild->RemoveGuildInvite(playerId, true);
	}
}

void GuildMgr::SendPacket2AllGuildMemeber(const INetPacket& pck, const Guild* pGuild)
{
	for (auto&[playerId, guildMember] : pGuild->GetGuildMembers()) {
		sTransMgr.SendPacket2ClientSafe(playerId, pck);
	}
}

void GuildMgr::SendPacket2AllGuildMemeber(const INetPacket& pck, const Guild* pGuild, uint32 authorities)
{
	for (auto&[playerId, guildMember] : pGuild->GetGuildMembers()) {
		if ((GuildTitleAuthorities[guildMember.guildTitle] & authorities) != 0) {
			sTransMgr.SendPacket2ClientSafe(playerId, pck);
		}
	}
}

std::pair<Guild*, GuildMember*> GuildMgr::GetGuildAndMemeber(uint32 playerId, uint32 guildId) const
{
	if (guildId != 0) {
		auto itr = m_guilds.find(guildId);
		if (itr != m_guilds.end()) {
			auto pGuild = itr->second;
			auto pGuildMember = pGuild->GetGuildMember(playerId);
			if (pGuildMember != NULL) {
				return {pGuild, pGuildMember};
			}
		}
	}
	for (auto&[Id, pGuild] : m_guilds) {
		auto pGuildMember = pGuild->GetGuildMember(playerId);
		if (pGuildMember != NULL) {
			return {pGuild, pGuildMember};
		}
	}
	return {NULL, NULL};
}

GuildMember* GuildMgr::GetGuildMemeber(uint32 playerId, uint32 guildId) const
{
	return GetGuildAndMemeber(playerId, guildId).second;
}

Guild* GuildMgr::GetGuild4Player(uint32 playerId, uint32 guildId) const
{
	return GetGuildAndMemeber(playerId, guildId).first;
}

Guild* GuildMgr::GetGuild(uint32 guildId) const
{
	auto itr = m_guilds.find(guildId);
	return itr != m_guilds.end() ? itr->second : NULL;
}

void GuildMgr::PushAllGuildRankDatas()
{
	MaxNetPacket pack(CGX_RANK_NEW_GUILD);
	int i = 0;
	for (auto&[Id, pGuild] : m_guilds) {
		pack << Id;
		for (int type = 0; type < (int)RANK_SUBTYPE::GUILD_COUNT; ++type) {
			PackGuildRankData(pack, pGuild, RANK_SUBTYPE(type));
		}
		if (++i >= 2500) {
			sPacketDispatcher.SendPacket2Rank(pack);
			pack.Clear();
			i = 0;
		}
	}
	if (i > 0) {
		sPacketDispatcher.SendPacket2Rank(pack);
	}
}

void GuildMgr::NewGuildRankData(const Guild* pGuild)
{
	NetPacket pack(CGX_RANK_NEW_GUILD);
	pack << pGuild->GetGuildId();
	for (int type = 0; type < (int)RANK_SUBTYPE::GUILD_COUNT; ++type) {
		PackGuildRankData(pack, pGuild, RANK_SUBTYPE(type));
	}
	sPacketDispatcher.SendPacket2Rank(pack);
}

void GuildMgr::UpdateGuildRankData(const Guild* pGuild, int subType)
{
	NetPacket pack(CGX_RANK_UPDATE_GUILD);
	if (subType == -1) {
		for (int type = 0; type < (int)RANK_SUBTYPE::GUILD_COUNT; ++type) {
			PackGuildRankData(pack, pGuild, RANK_SUBTYPE(type),
				(int)RankDataFlag::UID | (int)RankDataFlag::TYPE);
		}
	} else if (subType >= 0 && subType < (int)RANK_SUBTYPE::GUILD_COUNT) {
		PackGuildRankData(pack, pGuild, RANK_SUBTYPE(subType),
			(int)RankDataFlag::UID | (int)RankDataFlag::TYPE);
	}
	sPacketDispatcher.SendPacket2Rank(pack);
}

void GuildMgr::RemoveGuildRankData(const Guild* pGuild)
{
	NetPacket pack(CGX_RANK_REMOVE_GUILD);
	pack << pGuild->GetGuildId();
	sPacketDispatcher.SendPacket2Rank(pack);
}

void GuildMgr::PackGuildRankData(INetPacket& pck, const Guild* pGuild, RANK_SUBTYPE subType, int flags)
{
	if ((flags & (int)RankDataFlag::UID) != 0) {
		pck << pGuild->GetGuildId();
	}
	if ((flags & (int)RankDataFlag::TYPE) != 0) {
		pck << (uint8)subType;
	}
	auto& guildInfo = pGuild->GetGuildInformation();
	switch (subType) {
	case RANK_SUBTYPE::GUILD_LEVEL:
		pck << guildInfo.level << guildInfo.levelTime;
		break;
	case RANK_SUBTYPE::GUILD_FIGHT_VALUE:
		pck << pGuild->GetTotalFightValue() << pGuild->GetLastFightValueTime();
		break;
	}
}

GErrorCode GuildMgr::HandleGetGuildList(Coroutine::YieldContext& ctx, uint32 uid, uint32 startIndex, uint32 getCountMax)
{
	NetPacket rpcReqPck(CGX_RANK_GET_GUILD_ID_LIST);
	rpcReqPck << (u8)SocialRPCReply::Guild << (u8)RANK_SUBTYPE::GUILD_LEVEL
		<< startIndex << getCountMax;
	sPacketDispatcher.RPCInvoke2Rank(
		rpcReqPck, ctx.GetRPCInvokeCb(), this, DEF_S2S_RPC_TIMEOUT);
	auto resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}

	std::vector<uint32> guildIds;
	guildIds.reserve(getCountMax);
	while (!resp.pck->IsReadableEmpty()) {
		guildIds.push_back(resp.pck->Read<uint32>());
	}

	rpcReqPck.Reset(SGX_PULL_CHARACTER_INFOS);
	rpcReqPck << (u32)PullValueFlag::ExtraKey
		<< ((u32)CharValueType::Key | (u32)CharValueType::Name);
	for (auto guildId : guildIds) {
		auto pGuild = GetGuild(guildId);
		if (pGuild != NULL) {
			rpcReqPck << guildId << pGuild->GetGuildMaster();
		}
	}
	auto errCode = sGameServerMgr.RPCInvoke2GS(
		rpcReqPck, ctx.GetRPCInvokeCb(), this, DEF_S2S_RPC_TIMEOUT);
	if (errCode != RPCErrorNone) {
		return CommonInternalError;
	}
	resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}

	auto dataDict = RPCHelper::ReadReplyDataDict(*resp.pck);
	NetPacket toClient(SMSG_GUILD_GET_LIST_RESP);
	toClient << startIndex << (guildIds.size() >= getCountMax);
	for (auto guildId : guildIds) {
		auto pGuild = GetGuild(guildId);
		if (pGuild == NULL) {
			continue;
		}
		auto& dataStr = RPCHelper::TryGetReplyData(dataDict, guildId);
		if (dataStr.empty()) {
			continue;
		}
		auto& guildInfo = pGuild->GetGuildInformation();
		toClient << guildInfo.Id << guildInfo.name << guildInfo.createTime;
		toClient.Append(dataStr.data(), dataStr.size());
	}
	sTransMgr.SendPacket2ClientSafe(uid, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGetGuildInfo(Coroutine::YieldContext& ctx, uint32 guildId, uint32 uid)
{
	auto pGuild = GetGuild(guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, pGuild->GetGuildMaster(),
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	pGuild = GetGuild(guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	NetPacket toClient(SMSG_GUILD_GET_INFO_RESP);
	auto& guildInfo = pGuild->GetGuildInformation();
	toClient << guildInfo.Id << guildInfo.name << guildInfo.createTime;
	toClient.Append(dataStr.data(), dataStr.size());
	sTransMgr.SendPacket2ClientSafe(uid, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGetGuildMember(Coroutine::YieldContext& ctx, uint32 guildId, uint32 uid)
{
	auto pGuild = GetGuild(guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	NetPacket rpcReqPck(SGX_PULL_CHARACTER_INFOS);
	rpcReqPck << (u32)0 <<
		((u32)CharValueType::Key | (u32)CharValueType::Name |
		(u32)CharValueType::Level | (u32)CharValueType::FightValue |
		(u32)CharValueType::LastOnlineTime);
	for (auto&[playerId, guildMember] : pGuild->GetGuildMembers()) {
		rpcReqPck << playerId;
	}
	auto errCode = sGameServerMgr.RPCInvoke2GS(
		rpcReqPck, ctx.GetRPCInvokeCb(), this, DEF_S2S_RPC_TIMEOUT);
	if (errCode != RPCErrorNone) {
		return CommonInternalError;
	}
	auto resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}

	pGuild = GetGuild(guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	auto dataDict = RPCHelper::ReadReplyDataDict(*resp.pck);
	NetPacket toClient(SMSG_GUILD_GET_MEMBER_RESP);
	for (auto&[playerId, guildMember] : pGuild->GetGuildMembers()) {
		auto& dataStr = RPCHelper::TryGetReplyData(dataDict, playerId);
		if (dataStr.empty()) {
			continue;
		}
		toClient.Append(dataStr.data(), dataStr.size());
		toClient << guildMember.guildTitle << guildMember.joinTime;
	}
	sTransMgr.SendPacket2ClientSafe(uid, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGetGuildApply(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId)
{
	auto pGuild = GetGuild4Player(playerId, guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	NetPacket rpcReqPck(SGX_PULL_CHARACTER_INFOS);
	rpcReqPck << (u32)0 <<
		((u32)CharValueType::Key | (u32)CharValueType::Name |
		(u32)CharValueType::Level | (u32)CharValueType::FightValue |
			(u32)CharValueType::LastOnlineTime);
	for (auto&[playerId, guildApply] : pGuild->GetGuildApplys()) {
		rpcReqPck << playerId;
	}
	auto errCode = sGameServerMgr.RPCInvoke2GS(
		rpcReqPck, ctx.GetRPCInvokeCb(), this, DEF_S2S_RPC_TIMEOUT);
	if (errCode != RPCErrorNone) {
		return CommonInternalError;
	}
	auto resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}

	pGuild = GetGuild4Player(playerId, guildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}

	auto dataDict = RPCHelper::ReadReplyDataDict(*resp.pck);
	NetPacket toClient(SMSG_GUILD_GET_APPLY_RESP);
	for (auto&[playerId, guildApply] : pGuild->GetGuildApplys()) {
		auto& dataStr = RPCHelper::TryGetReplyData(dataDict, playerId);
		if (dataStr.empty()) {
			continue;
		}
		toClient.Append(dataStr.data(), dataStr.size());
		toClient << guildApply.applyTime;
	}
	sTransMgr.SendPacket2ClientSafe(playerId, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildInvite(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto pTgtGuild = GetGuild4Player(tgtPlayerId, tgtGuildId);
	if (pTgtGuild != NULL) {
		return ErrTargetAlreadyInGuild;
	}

	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if (pGuild->IsGuildMemberFull()) {
		return ErrGuildIsFull;
	}
	if ((GuildTitleAuthorities[pGuildMember->guildTitle] & (int)GUILD_AUTHORITY_TYPE::INVITE) == 0) {
		return ErrGuildAuthorityFailed;
	}
	if (pGuild->GetGuildInvites().count(tgtPlayerId) != 0) {
		return ErrAlreadyInGuildInviteList;
	}

	GuildInvite guildInvite{ playerId, tgtPlayerId, NewUniqueRoutineType() };
	CreateTimer(std::bind(&GuildMgr::OnInviteRelationExpire, this,
		guildId, tgtPlayerId), guildInvite.timer, GUILD_INVITE_TIMEOUT, 1);
	pGuild->AddGuildInvite(std::move(guildInvite));

	NetPacket toClient(SMSG_GUILD_INVITE);
	toClient << pGuild->GetGuildId() << pGuild->GetGuildName();
	toClient.Append(dataStr.data(), dataStr.size());
	sTransMgr.SendPacket2ClientSafe(tgtPlayerId, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildInviteResp(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, bool isAgree)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto pSelfGuild = GetGuild4Player(playerId, guildId);
	if (pSelfGuild != NULL && isAgree) {
		return ErrAlreadyInGuild;
	}

	auto pGuild = GetGuild(tgtGuildId);
	if (pGuild == NULL) {
		return ErrGuildIsDisband;
	}
	auto pGuildInvite = pGuild->GetGuildInvite(playerId);
	if (pGuildInvite == NULL) {
		return ErrGuildInviteExpired;
	}

	auto inviteInfo = std::move(*pGuildInvite);
	pGuild->RemoveGuildInvite(playerId);
	if (isAgree) {
		if (pGuild->IsGuildMemberFull()) {
			return ErrGuildIsFull;
		}
		AddGuildMember(pGuild, playerId, GUILD_JOIN_CAUSE::INVITE);
	}

	if (pGuild->GetGuildMembers().count(inviteInfo.inviterId) != 0) {
		NetPacket toClient(SMSG_GUILD_INVITE_RESP);
		toClient.Append(dataStr.data(), dataStr.size());
		toClient << isAgree;
		sTransMgr.SendPacket2ClientSafe(inviteInfo.inviterId, toClient);
	}

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildApply(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto pSelfGuild = GetGuild4Player(playerId, guildId);
	if (pSelfGuild != NULL) {
		return ErrAlreadyInGuild;
	}

	auto pGuild = GetGuild(tgtGuildId);
	if (pGuild == NULL) {
		return ErrTargetGuildNotExist;
	}
	if (pGuild->IsGuildMemberFull()) {
		return ErrGuildIsFull;
	}
	if (pGuild->GetGuildApplys().count(playerId) != 0) {
		return ErrAlreadyInGuildApplyList;
	}

	GuildApply guildApply;
	guildApply.playerId = playerId;
	guildApply.guildId = tgtGuildId;
	guildApply.applyTime = GET_UNIX_TIME;
	NetPacket rpcReqPck(CDBP_NEW_ONE_GUILD_APPLY);
	SaveToINetStream(guildApply, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);
	pGuild->AddGuildApply(std::move(guildApply));

	NetPacket toClient(SMSG_GUILD_APPLY);
	toClient.Append(dataStr.data(), dataStr.size());
	SendPacket2AllGuildMemeber(toClient, pGuild, (u32)GUILD_AUTHORITY_TYPE::REPLY);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildApplyResp(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtApplicantId, bool isAgree)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto pTgtGuild = GetGuild4Player(tgtApplicantId, tgtGuildId);
	if (pTgtGuild != NULL && isAgree) {
		return ErrTargetAlreadyInGuild;
	}

	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if ((GuildTitleAuthorities[pGuildMember->guildTitle] & (int)GUILD_AUTHORITY_TYPE::REPLY) == 0) {
		return ErrGuildAuthorityFailed;
	}
	auto pGuildApply = pGuild->GetGuildApply(tgtApplicantId);
	if (pGuildApply == NULL) {
		return ErrNotInGuildApplyList;
	}

	auto applyInfo = std::move(*pGuildApply);
	NetPacket rpcReqPck(CDBP_DELETE_GUILD_APPLY);
	rpcReqPck << applyInfo.playerId << applyInfo.guildId;
	sDBPSession.RPCInvoke(rpcReqPck);
	pGuild->RemoveGuildApply(tgtApplicantId);
	if (isAgree) {
		if (pGuild->IsGuildMemberFull()) {
			return ErrGuildIsFull;
		}
		AddGuildMember(pGuild, playerId, GUILD_JOIN_CAUSE::APPLY);
	}

	NetPacket toClient(SMSG_GUILD_APPLY_RESP);
	toClient.Append(dataStr.data(), dataStr.size());
	toClient << isAgree;
	sTransMgr.SendPacket2ClientSafe(tgtApplicantId, toClient);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildLeave(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if (pGuildMember->guildTitle == (int8)GUILD_TITLE::MASTER) {
		return ErrGuildMasterCantLeave;
	}

	NetPacket toClient(SMSG_GUILD_LEAVE_RESP);
	toClient.Append(dataStr.data(), dataStr.size());
	SendPacket2AllGuildMemeber(toClient, pGuild);

	RemoveGuildMember(pGuild, playerId, GUILD_QUIT_CAUSE::QUIT);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildKick(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId)
{
	std::unordered_map<uint32, std::string_view> dataDict;
	const uint32 playerIds[] = { playerId, tgtPlayerId };
	auto errCode = RPCHelper::RPCPullPlayerInfos(ctx, playerIds, ARRAY_SIZE(playerIds),
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataDict, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto[pTgtGuild, pTgtGuildMember] = GetGuildAndMemeber(tgtPlayerId, tgtGuildId);
	if (pTgtGuild == NULL) {
		return ErrTargetNotInGuild;
	}
	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if (pTgtGuild != pGuild) {
		return ErrNotInSameGuild;
	}
	if ((GuildTitleAuthorities[pGuildMember->guildTitle] & (int)GUILD_AUTHORITY_TYPE::KICK) == 0) {
		return ErrGuildAuthorityFailed;
	}
	if (pGuildMember->guildTitle >= pTgtGuildMember->guildTitle) {
		return ErrGuildAuthorityFailed;
	}

	NetPacket toClient(SMSG_GUILD_KICK_RESP);
	RPCHelper::PackRPCPlayerInfos(toClient, playerIds, ARRAY_SIZE(playerIds), dataDict);
	SendPacket2AllGuildMemeber(toClient, pGuild);

	RemoveGuildMember(pTgtGuild, tgtPlayerId, GUILD_QUIT_CAUSE::KICK);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildRise(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId, int8 guildTitle)
{
	std::unordered_map<uint32, std::string_view> dataDict;
	const uint32 playerIds[] = { playerId, tgtPlayerId };
	auto errCode = RPCHelper::RPCPullPlayerInfos(ctx, playerIds, ARRAY_SIZE(playerIds),
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataDict, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto[pTgtGuild, pTgtGuildMember] = GetGuildAndMemeber(tgtPlayerId, tgtGuildId);
	if (pTgtGuild == NULL) {
		return ErrTargetNotInGuild;
	}
	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if (pTgtGuild != pGuild) {
		return ErrNotInSameGuild;
	}
	if ((GuildTitleAuthorities[pGuildMember->guildTitle] & (int)GUILD_AUTHORITY_TYPE::RISE) == 0) {
		return ErrGuildAuthorityFailed;
	}
	if (pGuildMember->guildTitle >= pTgtGuildMember->guildTitle) {
		return ErrGuildAuthorityFailed;
	}
	if (pGuildMember->guildTitle >= guildTitle) {
		return ErrGuildAuthorityFailed;
	}
	if (pTgtGuildMember->guildTitle == guildTitle) {
		return CommonSuccess;
	}

	pTgtGuildMember->guildTitle = guildTitle;
	UpdateGuildMember(pTgtGuild, *pTgtGuildMember, GUILD_JOIN_CAUSE::RISE);

	NetPacket toClient(SMSG_GUILD_RISE_RESP);
	RPCHelper::PackRPCPlayerInfos(toClient, playerIds, ARRAY_SIZE(playerIds), dataDict);
	toClient << guildTitle;
	SendPacket2AllGuildMemeber(toClient, pGuild);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildDisband(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32& finalGuildId)
{
	std::string_view dataStr;
	auto errCode = RPCHelper::RPCPullPlayerInfo(ctx, playerId,
		(u32)CharValueType::Key | (u32)CharValueType::Name, dataStr, this);
	if (errCode != CommonSuccess) {
		return errCode;
	}

	auto[pGuild, pGuildMember] = GetGuildAndMemeber(playerId, guildId);
	if (pGuild == NULL) {
		return ErrNotInGuild;
	}
	if ((GuildTitleAuthorities[pGuildMember->guildTitle] & (int)GUILD_AUTHORITY_TYPE::DISBAND) == 0) {
		return ErrGuildAuthorityFailed;
	}

	NetPacket toClient(SMSG_GUILD_DISBAND_RESP);
	toClient.Append(dataStr.data(), dataStr.size());
	SendPacket2AllGuildMemeber(toClient, pGuild);

	finalGuildId = pGuild->GetGuildId();
	DisbandGuild(pGuild, playerId);

	return CommonSuccess;
}

GErrorCode GuildMgr::HandleTryGuildCreate(uint32 guildId, uint32 playerId)
{
	if (GetGuild4Player(playerId, guildId) != NULL) {
		return ErrAlreadyInGuild;
	}
	return CommonSuccess;
}

GErrorCode GuildMgr::HandleGuildCreate(uint32 gsId, uint32 guildId, uint32 playerId, uint32 newGuildId, const std::string_view& newGuildName)
{
	if (GetGuild4Player(playerId, guildId) != NULL) {
		return ErrAlreadyInGuild;
	}
	CreateGuild(gsId, playerId, newGuildId, newGuildName);
	return CommonSuccess;
}
